package com.envy.kickoffuserjson.config;

import com.envy.kickoffuserjson.bean.ResponseBean;
import com.envy.kickoffuserjson.entity.User;
import com.envy.kickoffuserjson.filter.EnvyLoginFilter;
import com.envy.kickoffuserjson.service.MyUserDetailService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.*;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.session.ConcurrentSessionFilter;

import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyUserDetailService myUserDetailService;

    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**","/login.html");
    }

    @Bean
    public EnvyLoginFilter envyLoginFilter() throws Exception {
        EnvyLoginFilter envyLoginFilter = new EnvyLoginFilter();
        //设置登录成功时的逻辑
        envyLoginFilter.setAuthenticationSuccessHandler((httpServletRequest,httpServletResponse,authentication)->{
            httpServletResponse.setContentType("application/json;charset=utf-8");
            PrintWriter out = httpServletResponse.getWriter();
            Map<String,Object> map = new HashMap<>();
            User user = (User) authentication.getPrincipal();
            user.setPassword(null);
            map.put("status",200);
            map.put("user",user);
            out.write(new ObjectMapper().writeValueAsString(map));
            out.flush();
            out.close();
        });

        envyLoginFilter.setAuthenticationFailureHandler((httpServletRequest,httpServletResponse,exception)->{
            httpServletResponse.setContentType("application/json;charset=utf-8");
            PrintWriter out = httpServletResponse.getWriter();
            Map<String,Object> map = new HashMap<>();
            map.put("status",401);
            if (exception instanceof LockedException) {
                map.put("msg", "账户被锁定，请联系管理员!");
            } else if (exception instanceof BadCredentialsException) {
                map.put("msg", "账户名或密码输入错误，请重新输入！");
            } else if (exception instanceof DisabledException) {
                map.put("msg", "账户被禁用，请联系管理员!");
            } else if (exception instanceof AccountExpiredException) {
                map.put("msg", "账户已过期，请联系管理员!");
            } else if (exception instanceof CredentialsExpiredException) {
                map.put("msg", "密码已过期，请联系管理员!");
            }
            else {
                map.put("msg", "登录失败！");
            }
            out.write(new ObjectMapper().writeValueAsString(map));
            out.flush();
            out.close();
        });
        envyLoginFilter.setAuthenticationManager(authenticationManagerBean());
        envyLoginFilter.setFilterProcessesUrl("/goLogin");
        ConcurrentSessionControlAuthenticationStrategy sessionStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
        sessionStrategy.setMaximumSessions(1);
        envyLoginFilter.setSessionAuthenticationStrategy(sessionStrategy);
        return envyLoginFilter;
    }

    @Bean
    SessionRegistryImpl sessionRegistry(){
        return new SessionRegistryImpl();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/goLogin")
                .permitAll()
                .and()
                .csrf().disable();
        http.addFilterAt(new ConcurrentSessionFilter(sessionRegistry(),event->{
            HttpServletResponse response = event.getResponse();
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(401);
            PrintWriter out = response.getWriter();
            out.write(new ObjectMapper().writeValueAsString(ResponseBean.error("您已在另一台设备登录，本次登录已下线!")));
            out.flush();
            out.close();
        }),ConcurrentSessionFilter.class);

        http.addFilterAt(envyLoginFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
